package com.bangdream.michelia.tool.retrofithttp;

import android.content.Context;
import android.os.Environment;

import com.bangdream.michelia.application.MainApplication;
import com.bangdream.michelia.entity.DownLoadInfo;
import com.bangdream.michelia.tool.rejava.BaseObserverResponseBodyNormalHttp;
import com.bangdream.michelia.tool.rejava.BaseObserverStringNormalHttp;
import com.bangdream.michelia.utils.FileUtil;
import com.bangdream.michelia.utils.MyLog;
import com.bangdream.michelia.utils.SuffixUtil;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.ObservableSource;
import io.reactivex.ObservableTransformer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
import okhttp3.ResponseBody;

/**
 * Created by Mr.Wang on 2017/12/15.
 * http://www.jianshu.com/p/582e0a4a4ee9
 */

public class DownLoadManager {
    private static final String TAG = "DownLoadManager";

    private static String APK_CONTENTTYPE = "application/vnd.android.package-archive";

    private static String PNG_CONTENTTYPE = "image/png";
    private static String JPG_CONTENTTYPE = "image/jpg";
    private static String JPG2_CONTENTTYPE = "application/x-jpg";
    private static String JPEG_CONTENTTYPE = "image/jpeg";
    private static String WORD_CONTENTTYPE = "application/ms-doc";

    public static String fileSuffix;
    //网络下载失败
    private static final int NETWORDFAIL = 10001;
    //文件写入失败
    private static final int WRITEFAIL = 10002;
    //未知错误
    private static final int UNKNOWNFAIL = 10002;
    //所有需要下载的文件地址
    //private List<DownLoadInfo> FileUrls = new ArrayList<>();
    //所有下载完成或失败的信息
    private List<DownLoadInfo> downLoadInfos = new ArrayList<DownLoadInfo>();
    //所有需要下载的文件数量
    private int AllFileNumber;
    //当前正在下载的文件下标
    private int UpLoadFileNumber;

    public DownLoadManager() {
    }

    //下载请求的RxJava设置
    ObservableTransformer composeFunction = new ObservableTransformer<Observable, ObservableSource>() {
        @Override
        public ObservableSource apply(Observable observable) {
            //retry方法是设置重试次数 不指定默认为0
            return observable.retry(1)
                    //将被观察者放在子线程，将观察者放在主线程
                    .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
                    //doOnSubscribe是在事件发送前进行的操作，所以我们可以做一些初始化的工作
                    .doOnSubscribe(new Consumer<Disposable>() {
                        @Override
                        public void accept(Disposable disposable) throws Exception {

                        }
                    });
        }
    };

    public static String writeResponseBodyToDisk(Context context, ResponseBody body, DownLoadInfo downLoadInfo) {

        MyLog.d(TAG, "contentType:>>>>" + body.contentType().toString());

        String type = body.contentType().toString();
        MyLog.d(TAG, "type=" + type);
        fileSuffix = downLoadInfo == null ? null : downLoadInfo.getFileSuffix();
        //如果传入的后缀不包含. 则增加在后缀前面
        if (fileSuffix != null && fileSuffix.length() > 0 && !fileSuffix.contains(".")) {
            fileSuffix = "." + fileSuffix;
        } else if (fileSuffix == null || fileSuffix.length() < 1) {
            if (type.equals(APK_CONTENTTYPE)) {
                fileSuffix = ".apk";
            } else if (type.equals(PNG_CONTENTTYPE)) {
                fileSuffix = ".png";
            } else if (type.equals(JPG_CONTENTTYPE)) {
                fileSuffix = ".jpg";
            } else if (type.equals(JPG2_CONTENTTYPE)) {
                fileSuffix = ".jpg";
            } else if (type.equals(JPEG_CONTENTTYPE)) {
                fileSuffix = ".jpeg";
            } else if (type.equals(WORD_CONTENTTYPE)) {
                fileSuffix = ".doc";
            }
        }
        // 其他类型同上 自己判断加入.....
        String path = null;
        try {
            //获取文件下载地址
            if (downLoadInfo.getLocalUrl() == null || downLoadInfo.getLocalUrl().length() < 1) {
                path = createDefaultImageFile(fileSuffix).getPath();
                MyLog.d(TAG, "path1:>>>>" + path);

            } else {
                path = downLoadInfo.getLocalUrl();
                MyLog.d(TAG, "path2:>>>>" + path);

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        MyLog.d(TAG, "path:>>>>" + path);

        try {
            // todo change the file location/name according to your needs
            File futureStudioIconFile = new File(path);

            InputStream inputStream = null;
            OutputStream outputStream = null;
            try {
                byte[] fileReader = new byte[4096];
                long fileSize = body.contentLength();
                long fileSizeDownloaded = 0;
                inputStream = body.byteStream();
                outputStream = new FileOutputStream(futureStudioIconFile);
                while (true) {
                    int read = inputStream.read(fileReader);
                    if (read == -1) {
                        break;
                    }
                    outputStream.write(fileReader, 0, read);

                    fileSizeDownloaded += read;

                    MyLog.d(TAG, "file download: " + fileSizeDownloaded + " of " + fileSize);
                }
                outputStream.flush();
                return path;
            } catch (IOException e) {
                return path;
            } finally {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (outputStream != null) {
                    outputStream.close();
                }
            }
        } catch (IOException e) {
            return path;
        }
    }

    public static File createDefaultImageFile(String fileSuffix) throws IOException {
//        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss",
//                Locale.getDefault()).format(new Date());
        String imageFileName = System.currentTimeMillis() + fileSuffix;
        ;
        File storageDir = new File(getSDPath());
//        File storageDir = Environment
//                .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
        if (!storageDir.exists()) {
            storageDir.mkdirs();
        }
        FileUtil.CreateFile();
        switch (SuffixUtil.SuffixToType(fileSuffix)) {
            case WORD:
                return new File(FileUtil.LocalPathDown + "/" + imageFileName);
            case PICTURE:
                return new File(getSDPath() + "/" + imageFileName);
            default:
                return new File(FileUtil.LocalPathDown + "/" + imageFileName);
        }
    }

    public static String getSDPath() {
        File sdDir = null;
        boolean sdCardExist = Environment.getExternalStorageState().equals(
                Environment.MEDIA_MOUNTED); // 判断sd卡是否存在
        if (sdCardExist) {
            sdDir = Environment.getExternalStorageDirectory();
        } else {
        }
        File eis = new File(sdDir.toString() + "/byl/");
        try {
            if (!eis.exists()) {
                eis.mkdir();
            }
        } catch (Exception e) {

        }
        return sdDir.toString() + "/byl/";
    }

    //下载单个文件
    private void downLoadStart(final String url) {
        MyLog.d(TAG, "下载地址为：" + url);
        final DownLoadInfo downLoadInfo = downLoadInfos.get(UpLoadFileNumber);
        Observable apiserice = RetroFactory.getInstance().downloadFile(url);
        apiserice.compose(composeFunction).subscribe(new BaseObserverResponseBodyNormalHttp(null, null) {
            @Override
            public void onHandleSuccess(final ResponseBody t) {
                Observable.create(new ObservableOnSubscribe<String>() {
                    @Override
                    public void subscribe(@NonNull ObservableEmitter<String> e) throws Exception {
                        String path = "";
                        if (downLoadInfo.getLocalUrl() != null && downLoadInfo.getLocalUrl().length() > 0) {
                            path = downLoadInfo.getLocalUrl();
                        } else {
                            path = DownLoadManager.writeResponseBodyToDisk(MainApplication.getContext(), t, downLoadInfo);
                        }
                        MyLog.d(TAG, "下载文件的本地地址为：" + path);
                        if (path != null && path.length() > 0) {
                            e.onNext(path);
                        } else {
                            e.onNext(null);
                        }
                        e.onComplete();
                    }
                })
                        //将被观察者切换到子线程
                        .subscribeOn(Schedulers.io())
                        //将观察者切换到主线程
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe(new Consumer<String>() {
                            @Override
                            public void accept(@NonNull String s) throws Exception {
                                MyLog.d(TAG, "文件地址为：" + s);
                                if (s != null && s.length() > 0) {
                                    File f = new File(s);
                                    if (f.exists()) {
                                        downLoadInfo.setNetUrl(url);
                                        downLoadInfo.setLocalUrl(s);
                                        downLoadInfo.setSuccess(true);
                                        downLoadInfo.setDescription(null);
                                        onDownLoadSuccess(s);
                                    } else {
                                        downLoadInfo.setNetUrl(url);
                                        downLoadInfo.setLocalUrl(s);
                                        downLoadInfo.setSuccess(false);
                                        downLoadInfo.setDescription("未知错误");
                                        downLoadInfo.setFailCode(UNKNOWNFAIL);
                                        onDownLoadError(UNKNOWNFAIL, "未知错误");
                                    }
                                } else {
                                    downLoadInfo.setNetUrl(url);
                                    downLoadInfo.setLocalUrl(s);
                                    downLoadInfo.setSuccess(false);
                                    downLoadInfo.setDescription("保存文件失败");
                                    downLoadInfo.setFailCode(WRITEFAIL);
                                    onDownLoadError(WRITEFAIL, "保存文件失败");
                                }
                            }
                        });
            }

            @Override
            public void onError(Throwable e) {
                onDownLoadError(NETWORDFAIL, "请求失败");
                super.onError(e);
            }
        });
    }


    public void onDownLoadSuccess(String path) {
        UpLoadFileNumber++;
        CyclicDownload();
    }

    public void onDownLoadError(int Code, String Description) {
        MyLog.d(TAG, "错误标识未：" + Code + "\n" + "错误描述为：" + Description);
        UpLoadFileNumber++;
        CyclicDownload();
    }

    //下载多个文件
    public void DownLoadListFile(List<DownLoadInfo> urls) {
        if (urls != null && urls.size() > 0) {
            downLoadInfos.clear();
            downLoadInfos = urls;
            AllFileNumber = urls.size();
            UpLoadFileNumber = 0;
            CyclicDownload();
        }
    }

    //通过当前下载数目的下标实现按顺序下载一个集合的文件
    private void CyclicDownload() {
        if (UpLoadFileNumber == AllFileNumber) {
            //全部下载完毕 无论其中成功失败多少
            DownLoadFileListComplete(downLoadInfos);
        } else {
            downLoadStart(downLoadInfos.get(UpLoadFileNumber).getNetUrl());
        }
    }

    public void DownLoadFileListComplete(List<DownLoadInfo> downLoadInfos) {
        MyLog.d(TAG, "文件下载完成的返回数据为：" + downLoadInfos.toString());
    }
}
